/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package compumundohipermegared;

import Tiempo.SntpClient;
import clasesJXTA.AdministradorJXTA;
import clasesJXTA.NodoRemoto;
import interfaz.InterfazFotosP2P;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;
import seguridad.ManejadorCertificados;
import sun.security.x509.X509CertImpl;

/**
 *
 * @author asistente
 */
public class Compumundohipermegared
{  
    /**
     * Veces que se envía el mensaje que indica que un peer terminó de recibir fotos
     * al momento de buscar foto mas parecida
     */
    public final static int VECES_REPETIR_MENSAJES=5;
    
    /**
     * carpeta donde se guardan las fotos
     */
    public final static String CARPETA_DE_FOTOS="./data/imagenes/";
     /**
     * carpeta donde se guardan las fotos
     */
    public final static String CARPETA_DE_ESTADOS="./data/estados/";
    
    public final static int SEGUNDOS_PARA_DESBLOQUEARSE=20;
  
   /**
    * arraList con las fotos que están en el equipo 
    */
    private ArrayList<Foto> fotosEnMiEquipo;
    
    /**
     * Servidor de tiempo utilizado
     */
    public final static String SERVIDOR_DE_TIEMPO="pool.ntp.org";
  
    
    /**
     * direccion  logica para los hosts en el mismo segmento de red
     */
    public final static String DIRECCION_MULTICAST="224.0.1.85";
    
     /**
     * direccion  logica para los hosts en el mismo segmento de red usada para guardar el estado
     */
    public final static String DIRECCION_MULTICAST_GUARDAR="224.0.1.86";
    /**
     * numero de respuestas limite para la busqueda por foto mas parecida
     */
    public final static int LIMITE_RESPUESTAS_FOTO_MAS_PARECIDA=20;
    
    /**
     * limite en segundos para la respuesta de la busqueda por foto mas parecida
     */
    public final static int LIMITE_TIEMPO_RESPUESTA_FOTO_MAS_PARECIDA_SEGUNDOS=10;
   
    /**
    * clase encargada de buscar fotos y descargarlas
    */
    private Buscador buscador;
    
    /**
     * variable que indica si el programa está bloqueado o no
     */
    private boolean bloqueado;
   
    /**
    * Clase encargada de enviar las fotos a otros peers 
    * y responder los advertisements 
    */
    private Compartidor compartidor;
    /**
     * clase que maneja el envío de mensajes de guardar el estado
     */
    private Guardador guardador;
   
    /**
     * Clase encargada de la administracion de JXTA
     */
    private AdministradorJXTA administradorJXTA;
   
    /**
     * referencia utilizada para poder actualizar la interfaz
     */
    private InterfazFotosP2P interfaz;
    /**
     * archivo que guarda el estado del sistema
     */
    private String archivoEstado;
    
    private final static String EXTENSION_ARCHIVO_GUARDAR=".data";
    
    private String nombreFoto;
    /**
     * indica si estaba descargando o no
     */
    private boolean estaDescargando;
    
    public String contrasenaEscogida;
    
   
    
    private String nombreUsuario;
    private int anchoImagen;
    private int altoImagen;
    private String idFoto;
    private boolean buscandoImagenMasParecida;
    private boolean estoyBuscandoLaFotoMasParecida;
    private int puntajeMinimo;
    private String idFotoMasParecida;
    private boolean tieneCertificado;
    
    /**
    * construye la clase nueva
    */
    public Compumundohipermegared( String nNombre ,  InterfazFotosP2P interfaz)throws Exception
    {
        nombreUsuario=nNombre;
        this.interfaz=interfaz;
        // crea el administrador de JXTA
        administradorJXTA = new AdministradorJXTA( nNombre );
        // crea un buscador
        buscador = new Buscador( administradorJXTA, this);       
        fotosEnMiEquipo= new ArrayList<Foto>( );
        // crea un compartAidor
        compartidor = new Compartidor( fotosEnMiEquipo, administradorJXTA , this);
        guardador = new Guardador(administradorJXTA, this);
        compartidor.start();
        estaDescargando=false;
        bloqueado=false;
        tieneCertificado = false;
        /**
         * les pregunta a los demás peers a ver si están bloqueados
         */
        buscador.preguntarSiEstanBloqueados();
    }
    
    public boolean tieneCertificado( )
    {
        return tieneCertificado;
    }
    
    /**
     * actualiza la interfaz con las fotos que hay en el equipo
     * y agrega al mundo una nueva foto
     */
    public void agregarFotoRecibida(Foto fotonueva){
        fotosEnMiEquipo.add(fotonueva);
        interfaz.actualizarFotosMias(fotosEnMiEquipo);
    }
    public void addObserver( Observer ob )
    {
        administradorJXTA.addObserver(ob);
    }
    
    public ArrayList<Foto> getFotosEnMiEquipo( )
    {
        return fotosEnMiEquipo;
    }

    public void setFotosEnMiEquipo( ArrayList<Foto> fotosEnMiEquipo ) 
    {
        this.fotosEnMiEquipo = fotosEnMiEquipo;
    }
    
    /**
     * agrega la foto y la publica
     * @param nID
     * @param nExt
     * @param nPersonas
     * @param nTiempoGenerada
     * @param nMia
     * @param rutaCompletaFoto 
     */
    public void agregarFoto( String nID, String nExt, String nPersonas, Date nTiempoGenerada, boolean nMia , String rutaCompletaFoto, int altoImagen, int anchoImagen )
    {
        Foto nuevaFoto = new Foto(nID, nExt, nPersonas, nTiempoGenerada, null, rutaCompletaFoto, true );
        nuevaFoto.setAltoImagen( altoImagen );
        nuevaFoto.setAnchoImagen( anchoImagen );
        fotosEnMiEquipo.add( nuevaFoto );
        publicarFoto( nuevaFoto );
        
        bloqueado=false;
    }
    
    public void publicarFoto( Foto foto )
    {
        try
        {
            administradorJXTA.publicarFoto( foto );
        }
        catch( Exception e )
        {
            System.out.println( "No se pudo publicar la foto: " +e.getMessage() );
        }
    }
    
    public void buscarPorID( String nID )
    {  
        administradorJXTA.buscarPorID( nID );    
    }
    
    public void buscarPorPersonas( String nPersonas )
    {
        administradorJXTA.buscarPorPersonas( nPersonas );    
    }

    public void descargarFoto( String nombreArchivo, NodoRemoto nodoRemoto ) throws IOException
    {   estaDescargando=true;
        this.nombreFoto = nombreArchivo;
        buscador.descargarFoto( nombreArchivo, nodoRemoto );  
        estaDescargando=false;
    }
    
    public void buscarFotoMasParecida( Foto foto )
    {
        estoyBuscandoLaFotoMasParecida = true;
        buscador.buscarFotoMasParecida( foto );
        System.out.println("buscarFotoMasParecida( foto ); 1");
    }
    /**
     * 
     * @return el nombre del archivo para guardar el estado
     */
    public String generarNombreArchivoGuardar( )
    {
        try 
        {
            String nombreArchivo = SntpClient.getDateUTC(SERVIDOR_DE_TIEMPO).toGMTString().replace(" ", "").replace(":", "-");
            System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAA " +nombreArchivo);
            return nombreArchivo+EXTENSION_ARCHIVO_GUARDAR;

        } 
        catch( Exception ex )
        {
            Logger.getLogger(Compumundohipermegared.class.getName()).log(Level.SEVERE, null, ex);
        }
        return "";
    }
    
    /**
     * Guarda el estado del programa
     * @param archivoEstado archivo que guarda el estado del sistema EL NOMBRE SOLAMENTE, NO LA RUTA COMPLETA
     */
    public void salvarEstado(String archivoEstado)
    {
        System.out.println("Salvando Estado...");
               
        ObjectOutputStream oos = null;
        try 
        {
            oos = new ObjectOutputStream( new FileOutputStream( CARPETA_DE_ESTADOS+archivoEstado ) );
            oos.writeObject( fotosEnMiEquipo);
            oos.writeObject(new Boolean(estaDescargando));
            if (estaDescargando){
                  oos.writeObject( nombreFoto );
            }
            
            oos.writeObject( new Boolean( buscandoImagenMasParecida ) );
            oos.writeObject( new Boolean( estoyBuscandoLaFotoMasParecida ) );
            oos.writeObject(new Integer(anchoImagen));
            oos.writeObject(new Integer(altoImagen));
            oos.writeObject(idFoto);
            oos.writeObject( new Integer(puntajeMinimo));
            oos.writeObject( idFotoMasParecida);
            //oos.writeObject( nodoRemoto );
            oos.close( );
        } 
        catch (IOException ex) 
        {
            ex.printStackTrace();
        } 

        
        System.out.println("Ya lo salvé");
    }
    
    /**
     * Carga el archivo del estado 
     * @param archivoEstado EL NOMBRE SOLAMENTE, NO LA RUTA COMPLETA
     */
    public void cargarEstado(String archivoEstado){
        
        File archEstado = new File( CARPETA_DE_ESTADOS+archivoEstado );
        
         try
         {
            ObjectInputStream ois = new ObjectInputStream( new FileInputStream( archEstado ) );
            fotosEnMiEquipo = ( ArrayList<Foto> )ois.readObject( );
            estaDescargando = (Boolean) ois.readObject();
            if(estaDescargando)
            {
                nombreFoto = ( String )ois.readObject( );
                
                buscarPorID( nombreFoto );
                interfaz.fotosPendientes( );
            }
            
            buscandoImagenMasParecida = ( Boolean )ois.readObject( );
            estoyBuscandoLaFotoMasParecida = ( Boolean )ois.readObject( );
            anchoImagen = ( Integer )ois.readObject( );
            altoImagen = ( Integer )ois.readObject( );
            idFoto = ( String )ois.readObject( );
            puntajeMinimo = ( Integer )ois.readObject( );
            idFotoMasParecida = ( String )ois.readObject( );
            
            System.out.println( "Informacion de la busqueda de la foto mas parecida" );
            System.out.println( "Ancho " + anchoImagen );
            System.out.println( "Alto " + altoImagen );
            System.out.println( "idFoto " + idFoto );
            System.out.println( "Puntaje minimo " + puntajeMinimo );
            System.out.println( "idFotoMasParecida " + idFotoMasParecida );
            System.out.println( "Estoy comparando fotos " + buscandoImagenMasParecida );
            System.out.println( "Estoy buscando la mas parecida " + estoyBuscandoLaFotoMasParecida );
            
            compartidor.acutalizarFotosEnMiEquipo(fotosEnMiEquipo);
            publicarFotos(fotosEnMiEquipo);
            interfaz.actualizarFotosMias(fotosEnMiEquipo);

            ois.close( );
            
            if( estoyBuscandoLaFotoMasParecida )
            {
                seguirBuscandoFotoMasParecida( puntajeMinimo, idFotoMasParecida );
            }
        }
        catch( Exception e )
        {
            e.printStackTrace();
        }
    }
    
    /**
     * bloquea al sistema porque alguien está buscando por foto mas parecida
     */
    void bloquearSistema()
    {
        if(!bloqueado){
            bloqueado=true;
            interfaz.bloquearSistema();
            Desbloqueador db = new Desbloqueador(this);
            db.start();
        }
      
        
    }
    
    /**
     * 
     */
    void desbloquear( )
    {
        bloqueado=false;
        interfaz.desbloquear( );
    }

    public void anunciarSalvarEstado(String nombreArchivoGuardar) {
        // anuncia que toca salvar el estado
        guardador.anunciarGuardarEstado(nombreArchivoGuardar);
    }
    /**
     * publica en advertisements las fotos del arraylist
     * @param fotosEnMiEquipo 
     */
    private void publicarFotos(ArrayList<Foto> fotosEnMiEquipo) {
        
        for (int i = 0; i < fotosEnMiEquipo.size(); i++) {
            Foto foto = fotosEnMiEquipo.get(i);
            
            publicarFoto(foto);
        }
    }
    /**
     * le anuncia a todo el mundo que carguen un estado
     * @param name 
     */
    public void anunciarCargarEstado(String archivoEstado) {
       guardador.anunciarCargarEstado(archivoEstado);
    }

    /**
     * @return the nombreUsuario
     */
    public String getNombreUsuario() {
        return nombreUsuario;
    }

    /**
     * @param nombreUsuario the nombreUsuario to set
     */
    public void setNombreUsuario(String nombreUsuario) {
        this.nombreUsuario = nombreUsuario;
    }

    void envioFotoMasParecida( )
    {
        buscandoImagenMasParecida = false;
    }

    void encontreLaFotoMasParecida() 
    {
        estoyBuscandoLaFotoMasParecida = false;
    }

    void actualizarPuntajeMinimo( int puntajeMinimo )
    {
        this.puntajeMinimo = puntajeMinimo;
    }

    private void seguirBuscandoFotoMasParecida( int puntajeMinimo, String idFotoMasParecida ) 
    {
        buscador.seguirBuscandoFotoMasParecida( puntajeMinimo, idFotoMasParecida );
    }

    boolean estaBuscandoFotoMasParecida( )
    {
        return buscandoImagenMasParecida;
    }

    int darAncho( )
    {
        return anchoImagen;
    }

    int darAlto( )
    {
        return altoImagen;
    }

    String darIdFoto( )
    {
        return idFoto;
    }

    void actualizarIdFotoMasParecida( String idFotoMasParecida )
    {
        this.idFotoMasParecida = idFotoMasParecida;
    }

    public void generarGertificado(String contraseniaLlavePrivada) 
    {
        tieneCertificado = true;
        contrasenaEscogida=contraseniaLlavePrivada;
        ManejadorCertificados.generarCertificadoPrimeraVez(contraseniaLlavePrivada, nombreUsuario);
        //X509CertImpl cert = ManejadorCertificados.leerCertificado("./data/David.cer");
        
        //System.out.println("Esta es la contraseña escogida");
        //System.out.println(contrasenaEscogida);
              
        
        //String textoCifrado = ManejadorCertificados.cifrarTextoConLlavePublica(cert.getPublicKey(), contrasenaEscogida);
        
         //System.out.println("Texto Cifrado");
        //System.out.println(textoCifrado);
    }
    
      
    public class Desbloqueador extends Thread
    {
        Compumundohipermegared padre;
        
        public Desbloqueador(Compumundohipermegared padre)
        {
            this.padre=padre;
        }
        
        public void run()
        {
            long tiempoInicial = System.currentTimeMillis();
            long tiempoFinal = System.currentTimeMillis();
            while (tiempoFinal-tiempoInicial < (1000 * SEGUNDOS_PARA_DESBLOQUEARSE)){
                tiempoFinal = System.currentTimeMillis();
            }
            padre.desbloquear();
        }
    }

    public void asignarDatosBuscarFotoMasParecida( int anchoImagen, int altoImagen, String idfoto )
    {
        this.anchoImagen = anchoImagen;
        this.altoImagen = altoImagen;
        this.idFoto = idfoto;
        buscandoImagenMasParecida = true;
    }
}